const express = require('express');
const fs = require("fs");
const bodyParser = require('body-parser');
const path = require("path");
const {v4: uuidv4} = require('uuid');
const basicAuth = require('express-basic-auth');
const Term = require('./obj/Term');
const {fileToDb} = require("./data/file_db_util");
const {MongoClient, ObjectId} = require("mongodb");
const {dbToFile} = require("./data/file_db_util");
const server = express();
const publicSrv = express();
server.set('view engine', 'ejs')
server.use(bodyParser.urlencoded({extended: false}))
server.use(bodyParser.json())

const DATA_CACHE = {
  data: [],
  ifModify: true
}
const mongo = {
  term: null
};
const url = process.env.MONGO_URL || 'mongodb://123.56.253.88:7779';
MongoClient.connect(url, (err, client) => {
  mongo.term = client.db("utools").collection('term');
  // mongo.term.deleteMany({})
  // fileToDb(mongo.term)
});

/**
 * 如果数据没有修改，则从缓存中读取
 * @param force
 * @returns {[]}
 */
function readTerm(force = false) {
  return new Promise(((resolve, reject) => {
    if (DATA_CACHE.ifModify || force) {
      DATA_CACHE.ifModify = false
      mongo.term.find({}).toArray().then(data => {
        DATA_CACHE.data = data
        resolve(data)
      }).catch(err => reject(err))
    } else {
      resolve(DATA_CACHE.data)
    }
  }))
}

/**
 * 启用 basic 验证
 */
server.use(basicAuth({
  authorizer: (username, password) => {
    return username === 'term' && password === 'term.123'
  },
  challenge: true
}))
server.use(express.static(path.join(__dirname, 'assets')));

server.get('/term', (req, res) => {
  res.render('admin', {})
});

/**
 * 刷新缓存
 */
server.post('/refresh', (req, res) => {
  readTerm(true)
  res.send(true)
})
server.post('/search', (req, res) => {
  const requestData = req.body;
  let words = requestData.words
  let cur = requestData.cur
  let size = requestData.size
  readTerm().then(data => {
    res.send(filterData(words, data, cur, size))
  })
})
publicSrv.get('/fullData', (req, res) => {
  readTerm().then(data => {
    res.send(data)
  })
})

function filterData(words, list, cur, size) {
  let result = list.filter(it => it.desc && it.desc.includes(words)
    || it.en_short?.toString()?.toLowerCase()?.includes(words.toLowerCase())
    || it.en_full?.toString()?.toLowerCase()?.includes(words.toLowerCase())
    || it.cn_short?.toString()?.toLowerCase()?.includes(words.toLowerCase())
    || it.cn_full?.toString()?.toLowerCase()?.includes(words.toLowerCase()));
  let offset = size * (cur - 1)
  return {
    data: result
      .sort((a, b) => a.en_short.toString().toLowerCase() > b.en_short.toString().toLowerCase() ? 0 : -1)
      .slice(offset, size * cur),
    paged: {
      total: result.length,
      cur: cur,
      size: size
    }
  }


}

function setModify() {
  DATA_CACHE.ifModify = true
}


function write(data) {
  fs.writeFile('./data/term.json', JSON.stringify(data, null, 2), (err) => {
    !err && setModify()
    console.log(err)
  })
}


server.post('/del', async (req, res) => {
  const requestData = req.body;
  let _id = requestData._id
  let result = await mongo.term.deleteMany({_id: new ObjectId(_id)})
  if(result.deletedCount === 0) {
    mongo.term.deleteMany({_id: _id})
  }
  setModify()
  res.send(true)
})

server.post('/add', async (req, res) => {
  let newOne = req.body;
  // newOne.en_short
  let obj = await mongo.term
    .findOne({en_short: newOne.en_short})
  if (obj) {
    res.send('exists')
    return;
  }
  mongo.term.insert(new Term(newOne))
  setModify()
  res.send(true)
})
server.post('/edit', async (req, res) => {
  let editOne = req.body;
  let obj = await mongo.term
    .findOne({en_short: editOne.en_short})
  if (obj && obj._id.toString() !== editOne._id) {
    res.send('exists')
    return;
  }
  if(editOne.en_short) {
    let result = await mongo.term.updateOne({_id: new ObjectId(editOne._id)},
      {
        $set: {
          en_short: editOne.en_short,
          en_full: editOne.en_full,
          cn_short: editOne.cn_short,
          cn_full: editOne.cn_full,
          desc: editOne.desc,
        }
      })
    if(result.modifiedCount === 0) {
      mongo.term.updateOne({_id: editOne._id},
        {
          $set: {
            en_short: editOne.en_short,
            en_full: editOne.en_full,
            cn_short: editOne.cn_short,
            cn_full: editOne.cn_full,
            desc: editOne.desc,
          }
        })
    }
  } else {
    res.send('null')
  }

  setModify()
  res.send(true)
})

server.listen(process.env.PRIVATE_PORT || 8000)
publicSrv.listen(process.env.PUBLIC_PORT || 8001)
